[iOS]リスト表示→グリッド表示の切り替えをアニメーション付きで行う方法
はじめに
こんにちは!
モバイルアプリサービス部の田中孝明です。
今回はリスト表示→グリッド表示の切り替えをアニメーション付きで行うTIPSをサンプルプログラム付きで書き記します。
商品一覧を閲覧する機能を作る際、商品の写真を強調して見せたいモードと商品名とサマリーを見せたいモードの切り替えを行いたいとの要望がありました。
その際の実装例として考案したものをまとめてみました。
サンプルプログラム
以下に公開しています。
実装例
便宜上、商品の写真だけ見せたいモードをグリッド表示、商品名とサマリーを見せたいモードをリスト表示と呼称します。
上記のモードをアニメーション付きで切り替えるためにはUICollectionViewを利用します。
UICollectionViewのUICollectionViewFlowLayoutを表示したいモードに合わせて切り替えることで、UITableViewのようにも利用することができます。
下記はリスト表示のUICollectionViewFlowLayoutです。
こうすると、UITableViewのような見た目にすることができます。
let layout = UICollectionViewFlowLayout() layout.itemSize = CGSize(width: rect.size.width, height: 60) layout.minimumLineSpacing = 0 layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) return layout
下記はグリッド表示のUICollectionViewFlowLayoutです。
let layout = UICollectionViewFlowLayout() layout.itemSize = CGSize(width: (rect.size.width - 30) / 2, height: (rect.size.width - 30) / 2) layout.minimumLineSpacing = 5 layout.minimumInteritemSpacing = 0 layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) return layout
あとはUICollectionViewCellを定義します。
ポイントとしてはリスト表示、グリッド表示共に同じUICollectionViewCellを利用します。
Autolayoutの制約(NSLayoutConstraint)をIBOutletで紐付けておくことで、表示変更時に制約を変更できるようにしておきます。
class ToggleCollectionCell: UICollectionViewCell { private var savedItem: Item? @IBOutlet weak var idLabel: UILabel! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var thumbnailImageView: UIImageView! @IBOutlet weak var bottomView: UIView! @IBOutlet weak var nameLabelCenterXLayoutConstraint: NSLayoutConstraint! @IBOutlet weak var nameLabelCenterYLayoutConstraint: NSLayoutConstraint! func configureWithItem(item: Item, cellType: CellType) { savedItem = item updateConstraintsWithCellType(cellType) } func updateConstraintsWithCellType(cellType: CellType) { if let item = savedItem { idLabel?.text = item.id nameLabel?.text = item.name } switch cellType { case .List: backgroundColor = UIColor.whiteColor() idLabel.textColor = UIColor.redColor() nameLabel.textColor = UIColor.blackColor() nameLabelCenterXLayoutConstraint?.constant = -100 nameLabelCenterYLayoutConstraint?.constant = 0 bottomView.hidden = false case .Grid: backgroundColor = UIColor.darkGrayColor() idLabel.textColor = UIColor.blueColor() nameLabel.textColor = UIColor.brownColor() nameLabelCenterXLayoutConstraint?.constant = 0 nameLabelCenterYLayoutConstraint?.constant = 50 bottomView.hidden = true } } }
各表示のレイアウトによってはかなりコードが煩雑になるかもですが。。。
あとは上記の設定を表示モード切り替え処理でUIViewのanimateWithDurationを利用すればAutolayoutの制約に従ってUICollectionViewCellがアニメーションしながら表示が切り替わります。
@IBAction func didTapToggleButtonItem(sender: AnyObject) { switch cellType { case .List: cellType = .Grid case .Grid: cellType = .List } UIView.animateWithDuration(0.5, animations: { [weak self] in guard let `self` = self else { return } self.collectionView?.collectionViewLayout = self.cellType.layoutFromSuperviewRect(self.collectionView!.frame) self.collectionView?.visibleCells().forEach { cell in guard let _cell = cell as? ToggleCollectionCell else { return } _cell.updateConstraintsWithCellType(self.cellType) } }, completion: { [weak self] _ in guard let `self` = self else { return } self.toggleButtonItem.title = self.cellType.toggleButtonItemTitle }) }
最後に
今回のネタに関しては利用シーンが限定されているとは思います。
AutolayoutとUIViewのanimateWithDurationの組み合わせを使えばある程度のアニメーションを作成することが可能であることが今回のTIPSになります。